async function loadDashboard() {
  const statusElements = {
    count: document.getElementById("record-count"),
    locationCount: document.getElementById("location-count"),
    missingBefore: document.getElementById("missing-before"),
    missingAfter: document.getElementById("missing-after"),
    statsTable: document.getElementById("stats-table"),
    r2Score: document.getElementById("r2-score"),
    mae: document.getElementById("mae"),
    trainSize: document.getElementById("train-size"),
    testSize: document.getElementById("test-size"),
    predictionTable: document.getElementById("prediction-table"),
  };

  const resetContent = () => {
    statusElements.count.textContent = "--";
    statusElements.locationCount.textContent = "--";
    statusElements.missingBefore.innerHTML = "";
    statusElements.missingAfter.innerHTML = "";
    statusElements.statsTable.innerHTML = "";
    statusElements.r2Score.textContent = "--";
    statusElements.mae.textContent = "--";
    statusElements.trainSize.textContent = "--";
    statusElements.testSize.textContent = "--";
    statusElements.predictionTable.innerHTML = "";
  };

  try {
    const response = await fetch("../outputs/report.json", { cache: "no-cache" });
    if (!response.ok) {
      throw new Error(`无法加载报告文件（${response.status}）`);
    }
    const report = await response.json();

    statusElements.count.textContent = report.record_count ?? 0;
    const locationDistribution = report.location_distribution ?? {};
    const locationKeys = Object.keys(locationDistribution);
    statusElements.locationCount.textContent = locationKeys.length;

    renderLocationChart(locationDistribution);
    renderMissingValues(statusElements.missingBefore, report.missing_values?.before ?? {});
    renderMissingValues(statusElements.missingAfter, report.missing_values?.after ?? {});
    renderStatisticsTable(statusElements.statsTable, report.summary_statistics ?? {});
    renderModelMetrics(statusElements, report.model ?? {});
  } catch (error) {
    resetContent();
    showErrorToast(error.message);
    // eslint-disable-next-line no-console
    console.error(error);
  }
}

function renderMissingValues(target, data) {
  target.innerHTML = "";
  const entries = Object.entries(data).filter(([, value]) => Number(value) > 0);
  if (entries.length === 0) {
    const item = document.createElement("li");
    item.textContent = "无缺失值";
    target.appendChild(item);
    return;
  }
  entries.forEach(([key, value]) => {
    const item = document.createElement("li");
    item.textContent = `${key}: ${value}`;
    target.appendChild(item);
  });
}

function renderStatisticsTable(target, stats) {
  target.innerHTML = "";
  Object.entries(stats).forEach(([feature, metrics]) => {
    const row = document.createElement("tr");
    row.innerHTML = `
      <td>${feature}</td>
      <td>${formatNumber(metrics.mean)}</td>
      <td>${formatNumber(metrics.median)}</td>
      <td>${formatNumber(metrics.std)}</td>
      <td>${formatNumber(metrics.min)}</td>
      <td>${formatNumber(metrics.max)}</td>
    `;
    target.appendChild(row);
  });
}

function renderModelMetrics(statusElements, model) {
  const metrics = model.metrics ?? {};
  statusElements.r2Score.textContent = formatNumber(metrics.r2_score);
  statusElements.mae.textContent = formatNumber(metrics.mae);
  statusElements.trainSize.textContent = metrics.train_size ?? "--";
  statusElements.testSize.textContent = metrics.test_size ?? "--";

  const predictions = metrics.latest_predictions ?? [];
  statusElements.predictionTable.innerHTML = "";

  if (predictions.length === 0) {
    const row = document.createElement("tr");
    const cell = document.createElement("td");
    cell.colSpan = 3;
    cell.textContent = "暂无预测结果，请先运行 analysis.py";
    row.appendChild(cell);
    statusElements.predictionTable.appendChild(row);
    return;
  }

  predictions.forEach((item) => {
    const row = document.createElement("tr");
    row.innerHTML = `
      <td>${formatNumber(item.area)}</td>
      <td>${formatCurrency(item.actual_price)}</td>
      <td>${formatCurrency(item.predicted_price)}</td>
    `;
    statusElements.predictionTable.appendChild(row);
  });
}

function renderLocationChart(distribution) {
  const ctx = document.getElementById("location-chart");
  if (!ctx) return;

  const labels = Object.keys(distribution);
  const values = Object.values(distribution).map((value) => Number(value));

  if (window.locationChart) {
    window.locationChart.destroy();
  }

  window.locationChart = new Chart(ctx, {
    type: "doughnut",
    data: {
      labels,
      datasets: [
        {
          data: values,
          backgroundColor: ["#2a6efd", "#4fd1c5", "#f6ad55", "#ed64a6", "#9f7aea"],
        },
      ],
    },
    options: {
      responsive: true,
      maintainAspectRatio: true,
      aspectRatio: 1,
      layout: {
        padding: 8,
      },
      plugins: {
        legend: {
          position: "bottom",
          labels: {
            boxWidth: 12,
            boxHeight: 12,
            padding: 12,
            font: {
              size: 12,
            },
          },
        },
      },
    },
  });
}

function formatNumber(value) {
  if (value === undefined || value === null || Number.isNaN(Number(value))) {
    return "--";
  }
  return Number(value).toLocaleString("zh-CN", {
    maximumFractionDigits: 2,
  });
}

function formatCurrency(value) {
  if (value === undefined || value === null || Number.isNaN(Number(value))) {
    return "--";
  }
  return Number(value).toLocaleString("zh-CN", {
    style: "currency",
    currency: "CNY",
    maximumFractionDigits: 0,
  });
}

function showErrorToast(message) {
  const toast = document.createElement("div");
  toast.className = "toast";
  toast.textContent = message;
  document.body.appendChild(toast);
  setTimeout(() => toast.classList.add("visible"), 50);
  setTimeout(() => {
    toast.classList.remove("visible");
    setTimeout(() => {
      toast.remove();
    }, 300);
  }, 3200);
}

document.addEventListener("DOMContentLoaded", loadDashboard);
